package com.rparoxysm.tribase.weather;

import com.rparoxysm.util.Debug;
import com.rparoxysm.tribase.data.types.WeatherCondition;
import com.rparoxysm.tribase.data.types.WeatherConditionException;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public class WeatherConditionHandler extends DefaultHandler {
    private static final String CLASS_NAME = "WeatherConditionHandler";
    private static Debug debug = new Debug(CLASS_NAME);
    private static SAXParserFactory factory = SAXParserFactory.newInstance();

    private String tag;
    private SAXParser saxParser;
    private WeatherCondition condition;
    private List conditionList;

    public WeatherConditionHandler() {
	tag = "";
	condition = null;
	conditionList = null;

	try {
	    saxParser = factory.newSAXParser();
	} catch( ParserConfigurationException pce ) {
	    debug.print(Debug.ERROR, pce.getMessage());
	    pce.printStackTrace();
	} catch( SAXException se ) {
	    debug.print(Debug.ERROR, se.getMessage());
	    se.printStackTrace();
	}
    }
        
    public void startDocument() throws SAXException {
    }
    
    public void endDocument() throws SAXException {
    }
    
    public void startElement(String namespaceURI, 
			     String simpleName,
			     String qualifiedName,
			     Attributes attrs) 
	throws SAXException {
	String elementName = simpleName;
	if("".equals(elementName)) {
	    elementName = qualifiedName;
	}
	
	debug.print(Debug.INFO, "Opening tag " + elementName);
	tag = elementName;
	
	textBuffer = null;

	if(attrs != null) {
	    for(int i = 0; i < attrs.getLength(); ++i) {
		String attributeName = attrs.getLocalName(i);
		if("".equals(attributeName)) {
		    attributeName = attrs.getQName(i);
		}
		
		debug.print(Debug.INFO, "\t '" + attributeName + "' = '" +
			    attrs.getValue(i) + "'");
	    }
	}
    }
    
    public void endElement(String namespaceURI,
			   String simpleName,
			   String qualifiedName) 
	throws SAXException {
	debug.print(Debug.INFO, "element text: '" + 
		    ((textBuffer != null) ? textBuffer.toString() : "") + "'");

	if(conditionList == null) {
	    conditionList = new ArrayList();
	}

	if(condition == null) {
	    condition = new WeatherCondition();
	}
	
	String element = simpleName;
	if ("".equals(element)) element = qualifiedName;

	try {
	    if(element == "current_observation") {
		// observation data is complete add it to list of conditions
		conditionList.add(condition);
		condition = null;
	    } else if(tag == "credit") {
	    } else if(tag == "credit_URL") {
	    } else if(tag == "image") {
	    } else if(tag == "url") {
	    } else if(tag == "title") {
	    } else if(tag == "link") {
	    } else if(tag == "suggested_pickup") {
	    } else if(tag == "suggested_pickup_period") {
	    } else if(tag == "location") {
	    } else if(tag == "station_id") {
		condition.setStation(textBuffer.toString());
	    } else if(tag == "latitude") {
	    } else if(tag == "longitude") {
	    } else if(tag == "observation_time") {
	    } else if(tag == "observation_time_rfc822") {
		GregorianCalendar dtg = new GregorianCalendar();
		SimpleDateFormat sdf = 
		    new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
		ParsePosition pos = new ParsePosition(0);
		Date date = sdf.parse(textBuffer.toString(), pos);
		if(date != null) {
		    dtg.setTime(date);
		} else {
		    throw new ParseException("Unable to parse date '" + 
					     textBuffer.toString() + "'", 
					     pos.getIndex());
		}
		condition.setTime(dtg);
	    } else if(tag == "weather") {
		condition.setWeather(textBuffer.toString());
	    } else if(tag == "temperature_string") {
	    } else if(tag == "temp_f") {
		condition.setTemperature(
		    Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "temp_c") {
	    } else if(tag == "relative_humidity") {
		condition.setHumidity(Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "wind_string") {
	    } else if(tag == "wind_dir") {
		condition.setWindDirection(textBuffer.toString());
	    } else if(tag == "wind_degrees") {
		condition.setWindDirectionDegrees(
		    Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "wind_mph") {
		condition.setWindSpeed(
	            Double.parseDouble(textBuffer.toString()));
	    } else if(tag == "wind_gust_mph") {
		condition.setWindGust(Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "pressure_string") {
	    } else if(tag == "pressure_mb") {
	    } else if(tag == "pressure_in") {
		condition.setPressure(
		    Double.parseDouble(textBuffer.toString()));
	    } else if(tag == "dewpoint_f") {
		condition.setDewpoint(Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "dewpoint_c") {
	    } else if(tag == "dewpoint_string") {
	    } else if(tag == "heat_index_string") {
	    } else if(tag == "heat_index_f") {
		condition.setHeatIndex(Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "heat_index_c") {
	    } else if(tag == "windchill_string") {
	    } else if(tag == "windchill_f") {
		condition.setWindchill(Integer.parseInt(textBuffer.toString()));
	    } else if(tag == "windchill_c") {
	    } else if(tag == "visibility_mi") {
		condition.setVisibility(
                    Double.parseDouble(textBuffer.toString()));
	    } else if(tag == "icon_url_base") {
	    } else if(tag == "icon_url_name") {
		condition.setIconName(textBuffer.toString());
	    } else if(tag == "two_day_history_url") {
	    } else if(tag == "ob_url") {
	    } else if(tag == "disclaimer_url") {
	    } else if(tag == "copyright_url") {
	    } else if(tag == "privacy_policy_url") {
	    } else if(tag == "") {
		debug.print(Debug.ALL, "Empty tag");
	    } else {
		debug.print(Debug.WARN, "closing unknown tag '" + tag + "'");
	    }
	} catch (NumberFormatException nfe) {
	    int dbg = (textBuffer.toString() == "NA") ? Debug.ALL : Debug.WARN;
	    debug.print(dbg, "Error parsing tag '" + tag + "': " +
			nfe.getMessage() + "\n" + nfe.getStackTrace());
	} catch (ParseException pe) {
	    int dbg = (textBuffer.toString() == "NA") ? Debug.ALL : Debug.WARN;
	    debug.print(dbg, "Error parsing tag '" + tag + "': " +
			pe.getMessage() + "\n" + pe.getStackTrace());
	}

	tag = "";
	textBuffer = null;
    }
    
    private StringBuffer textBuffer;
    public void characters(char buf[], int offset, int len)
	throws SAXException {
	if(tag != "") {
	    String s = new String(buf, offset, len);
	    debug.print(Debug.INFO, "Adding '" + s + "'");
	    if(textBuffer == null) {
		textBuffer = new StringBuffer(s);
	    } else {
		textBuffer.append(s);
	    }
	}
    }

    public List parseXml(String uri) throws WeatherConditionException {
	try {
	    conditionList = null;
	    condition = null;
	    saxParser.parse(uri, this);
	} catch (IOException ioe) {
	    debug.print(Debug.WARN, "Error reading uri: " + ioe.getMessage());
	} catch (Throwable t) {
	    t.printStackTrace();
	    throw new WeatherConditionException("Could not parse");
	}
	return conditionList;
    }

    public static void main(String args[]) {
	if(args.length != 1) {
	    debug.print(Debug.ERROR, "Usage: java WeatherConditionHandler filename");
	    System.exit(1);
	}

	Debug.setLevel(CLASS_NAME, Debug.ERROR);

	try {
	    WeatherConditionHandler handler = new WeatherConditionHandler();
	    List conditions = handler.parseXml(args[0]);

	    Iterator cond = conditions.iterator();
	    while(cond.hasNext()) {
		debug.print(0, "\n" + cond.next() + "\n");
	    } 
	} catch (Throwable t) {
	    t.printStackTrace();
	}
	
	System.exit(0);
    }

    private int parseMonth(String month) throws ParseException {
	int num = 0;

	if(month.equals("Jan")) {
	    num = Calendar.JANUARY;
	} else if(month.equals("Feb")) {
	    num = Calendar.FEBRUARY;
	} else if(month.equals("Mar")) {
	    num = Calendar.MARCH;
	} else if(month.equals("Apr")) {
	    num = Calendar.APRIL;
	} else if(month.equals("May")) {
	    num = Calendar.MAY;
	} else if(month.equals("Jun")) {
	    num = Calendar.JUNE;
	} else if(month.equals("Jul")) {
	    num = Calendar.JULY;
	} else if(month.equals("Aug")) {
	    num = Calendar.AUGUST;
	} else if(month.equals("Sep")) {
	    num = Calendar.SEPTEMBER;
	} else if(month.equals("Oct")) {
	    num = Calendar.OCTOBER;
	} else if(month.equals("Nov")) {
	    num = Calendar.NOVEMBER;
	} else if(month.equals("Dec")) {
	    num = Calendar.DECEMBER;
	} else {
	    throw new ParseException("Unable to parse month '" + month + "'", 0);
	}

	return num;
    }
}
